package com.wanwu.channel.server.controller.mock;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.wanwu.channel.common.exception.SystemException;
import com.wanwu.channel.common.util.LogUtil;
import com.wanwu.channel.common.util.XmlUtil;

import com.wanwu.channel.dao.entity.ChannelPayEntity;
import com.wanwu.channel.dao.entity.ChannelRefundEntity;
import com.wanwu.channel.dao.inter.ChannelPayDao;
import com.wanwu.channel.dao.inter.ChannelRefundDao;
import com.wanwu.channel.common.util.IdGenerate;
import com.wanwu.channel.remote.wxpay.config.WeixinGlobalConfig;
import com.wanwu.channel.remote.wxpay.util.WXPayUtil;
import com.wanwu.channel.remote.wxpay.util.WechatSignUtil;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName WechatHttpsMock
 * @Description 微信接口挡板
 * @Author husheng
 * @Date 2020-01-08 14:08
 */
@Controller
@EnableConfigurationProperties(WeixinGlobalConfig.class)
@RequestMapping("/mock/line")
public class WechatHttpsMock {

    private static Logger logger = LoggerFactory.getLogger(WechatHttpsMock.class);

    @Autowired
    private WeixinGlobalConfig weixinGlobalConfig;

    @Resource
    private ChannelPayDao channelPayDao;

    @Resource
    private ChannelRefundDao channelRefundDao;

    /**
     * 微信统一下单接口挡板
     * @param req
     * @return
     */
    @RequestMapping(value = "/prepay", method = RequestMethod.POST)
    @ResponseBody
    public String mockPrepay(HttpServletRequest req){
        try {
            String reqXml = getRequestString(req);
            LogUtil.info(logger, "微信预下单mock开始，收到入参{0}", reqXml);
            Map<String, String> reqParam = WXPayUtil.xmlToMap(reqXml);
            Map<String, String> respParam = new HashMap<>();
            buildCommonResp(respParam, reqParam);
            respParam.put("trade_type", "APP");
            respParam.put("prepay_id", IdGenerate.getOrderId());
            String respXml = makeResultString(respParam);
            LogUtil.info(logger, "微信预下单mock结束，出参{0}", respXml);
            //延迟回调
            new Thread(() ->{ notifyPayResult(reqParam.get("out_trade_no"));}).start();
            return respXml;
        }catch (Exception e){
            LogUtil.error(logger, e, "微信预下单mock失败了");
            throw new SystemException();
        }finally {

        }
    }

    /**
     * 微信订单结果查询接口挡板
     * @param req
     * @return
     */
    @RequestMapping(value = "/payQuery", method = RequestMethod.POST)
    @ResponseBody
    public String mockPayQuery(HttpServletRequest req){
        try {
            String reqXml = getRequestString(req);
            LogUtil.info(logger, "微信订单结果查询mock开始，收到入参{0}", reqXml);
            Map<String, String> reqParam = WXPayUtil.xmlToMap(reqXml);
            Map<String, String> respParam = new HashMap<>();
            buildCommonResp(respParam, reqParam);
            respParam.put("openid", IdGenerate.getOrderId());
            respParam.put("is_subscribe", "Y");
            respParam.put("trade_type", "APP");
            respParam.put("trade_state", "SUCCESS");
            respParam.put("bank_type", "CBC");
            respParam.put("total_fee", "10005");
            respParam.put("out_trade_no", reqParam.get("out_trade_no"));
            respParam.put("transaction_id", IdGenerate.getOrderId());
            respParam.put("time_end", "20200109000000");
            respParam.put("trade_state_desc", "挡板返回成功");
            String respXml = makeResultString(respParam);
            LogUtil.info(logger, "微信订单结果查询mock结束，出参{0}", respXml);
            return respXml;
        }catch (Exception e){
            LogUtil.error(logger, e, "微信订单结果查询mock失败了");
            throw new SystemException();
        }
    }

    /**
     * mock微信关单
     * @param req
     * @return
     */
    @RequestMapping(value = "/closeOrder", method = RequestMethod.POST)
    @ResponseBody
    public String mockCloseOrder(HttpServletRequest req){
        try {
            String reqXml = getRequestString(req);
            LogUtil.info(logger, "微信关单mock开始，收到入参{0}", reqXml);
            Map<String, String> reqParam = WXPayUtil.xmlToMap(reqXml);
            Map<String, String> respParam = new HashMap<>();
            buildCommonResp(respParam, reqParam);
            respParam.put("result_msg", "挡板返回成功");
            String respXml = makeResultString(respParam);
            LogUtil.info(logger, "微信关单mock结束，出参{0}", respXml);
            return respXml;
        }catch (Exception e){
            LogUtil.error(logger, e, "微信关单mock失败了");
            throw new SystemException();
        }
    }

    /**
     * mock微信申请退款
     * @param req
     * @return
     */
    @RequestMapping(value = "/applyRefund", method = RequestMethod.POST)
    @ResponseBody
    public String mockApplyRefund(HttpServletRequest req){
        try {
            String reqXml = getRequestString(req);
            LogUtil.info(logger, "微信申请退款mock开始，收到入参{0}", reqXml);
            Map<String, String> reqParam = WXPayUtil.xmlToMap(reqXml);
            Map<String, String> respParam = new HashMap<>();
            buildCommonResp(respParam, reqParam);
            respParam.put("transaction_id", reqParam.get("transaction_id"));
            respParam.put("out_trade_no", reqParam.get("out_trade_no"));
            respParam.put("out_refund_no", reqParam.get("out_refund_no"));
            respParam.put("refund_id", IdGenerate.getOrderId());
            respParam.put("refund_fee", reqParam.get("refund_fee"));
            respParam.put("total_fee", reqParam.get("total_fee"));
            respParam.put("cash_fee", "0");
            String respXml = makeResultString(respParam);
            LogUtil.info(logger, "微信申请退款mock结束，出参{0}", respXml);
            return respXml;
        }catch (Exception e){
            LogUtil.error(logger, e, "微信申请退款mock失败了");
            throw new SystemException();
        }
    }

    /**
     * mock微信申请退款查询
     * @param req
     * @return
     */
    @RequestMapping(value = "/queryRefund", method = RequestMethod.POST)
    @ResponseBody
    public String mockQueryRefund(HttpServletRequest req){
        try {
            String reqXml = getRequestString(req);
            LogUtil.info(logger, "微信申请退款查询mock开始，收到入参{0}", reqXml);
            Map<String, String> reqParam = WXPayUtil.xmlToMap(reqXml);
            Map<String, String> respParam = new HashMap<>();
            buildCommonResp(respParam, reqParam);
            ChannelRefundEntity refund = channelRefundDao.selectOneByRefundNo(reqParam.get("out_refund_no"));
//            respParam.put("transaction_id", refund.getTradeNo());
//            respParam.put("out_trade_no", refund.getOutTradeNo());
//            respParam.put("total_fee", refund.getTotalFee() + "");
//            respParam.put("cash_fee", "0");
//            respParam.put("refund_count", refund.getRetryTimes() + 1 + "");
//            respParam.put("out_refund_no_0", refund.getOutReturnNo());
//            respParam.put("refund_id_0", refund.getThirdRefundNo());
//            respParam.put("refund_fee_0", refund.getRefundFee().toString());
            respParam.put("refund_status_0", "SUCCESS");
            respParam.put("refund_success_time_0", "2020-01-09 15:26:26");
            String respXml = makeResultString(respParam);
            LogUtil.info(logger, "微信申请退款查询mock结束，出参{0}", respXml);
            return respXml;
        }catch (Exception e){
            LogUtil.error(logger, e, "微信申请退款查询mock失败了");
            throw new SystemException();
        }
    }

    /**
     * 回调支付结果
     * @param outTradeNo
     */
    public void notifyPayResult(String outTradeNo){
        try {
            //睡个五秒钟再回调
            Thread.sleep(5000);
        }catch (Exception e){
            LogUtil.info(logger, "回调支付结果sleep5秒钟失败");
        }
        ChannelPayEntity pay = channelPayDao.queryByBizOrderNo(outTradeNo,"wanlimu_test");
        Map<String, String> reqParam = new HashMap<>();
        reqParam.put("return_code", "SUCCESS");
        reqParam.put("return_msg", "OK");
        reqParam.put("appid", "wx8944b93cddd094ee");
        reqParam.put("mch_id", "1575838551");
        reqParam.put("nonce_str", WXPayUtil.generateNonceStr());
        reqParam.put("result_code", "SUCCESS");
        reqParam.put("openid", IdGenerate.getOrderId());
        reqParam.put("is_subscribe", "Y");
        reqParam.put("trade_type", "APP");
        reqParam.put("bank_type", "CBC");
        reqParam.put("total_fee", pay.getRmbAmount() + "");
        reqParam.put("cash_fee", "0");
        reqParam.put("transaction_id", IdGenerate.getOrderId());
        reqParam.put("out_trade_no", pay.getBizOrderNo());
        reqParam.put("time_end", "20200109000000");
        JSONObject reqObj = JSONObject.parseObject(JSONObject.toJSONString(reqParam));
        WechatSignUtil.sign(reqObj, weixinGlobalConfig.getApiKey());
        XmlResponse reqDto = changeXmlRoot(reqObj);
        String reqXml = XmlUtil.toXml(reqDto);
        LogUtil.info(logger, "微信支付结果回调mock请求报文：{0}", reqXml);
        HttpRequest request = HttpRequest.post("http://10.11.3.140:9933/wechat/pay/notify")
                .header("Content-Type", "application/xml")
                .bodyText(reqXml);
        HttpResponse response = request.send();
        String responseBody = response.bodyText();
        LogUtil.info(logger, "微信支付结果回调mock结束，收到应答：{0}", responseBody);
    }

    /**
     * 公共返回组装
     * @param respParam
     * @param reqParam
     */
    private void buildCommonResp(Map<String, String> respParam, Map<String, String> reqParam){
        respParam.put("return_code", "SUCCESS");
        respParam.put("appid", reqParam.get("appid"));
        respParam.put("mch_id", reqParam.get("mch_id"));
        respParam.put("nonce_str", WXPayUtil.generateNonceStr());
        respParam.put("result_code", "SUCCESS");
    }

    /**
     * 组返回报文xml
     * @param respParam
     * @return
     */
    private String makeResultString(Map<String, String> respParam){
        JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(respParam));
        WechatSignUtil.sign(obj, weixinGlobalConfig.getApiKey());
        XmlResponse response = changeXmlRoot(obj);
        return XmlUtil.toXml(response);
    }

    /**
     * xml根结点转换
     * @param obj
     */
    private XmlResponse changeXmlRoot(JSONObject obj){
        XmlResponse result = new XmlResponse();
        for(String key : obj.keySet()){
            result.put(key, obj.get(key));
        }
        return result;
    }

    /**
     * 从HttpServletRequest中获取xml报文
     * @param request
     * @return
     * @throws IOException
     */
    private String getRequestString(HttpServletRequest request) throws IOException {
        //读取微信回调报文
        ServletInputStream instream = request.getInputStream();
        StringBuffer sb = new StringBuffer();
        int len = -1;
        byte[] buffer = new byte[1024];
        while ((len = instream.read(buffer)) != -1) {
            sb.append(new String(buffer, 0, len));
        }
        instream.close();
        return sb.toString();
    }
    @JacksonXmlRootElement(localName = "xml")
    public static class XmlResponse extends JSONObject{

    }

    public static void main(String[] args){
        XmlResponse obj = new XmlResponse();
        obj.put("result_code", "SUCCESS");
        obj.put("trade_type", "APP");
        System.out.println(XmlUtil.toXml(obj));
    }
}
